package com.cool.common.utils;

import okhttp3.*;
import okio.BufferedSink;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class HttpClientBuilder {

    private final Logger logger = LoggerFactory.getLogger(HttpClientBuilder.class);

    private final OkHttpClient client;
    private final Request.Builder requestBuilder;
    private String baseUrl;
    private final Map<String, String> pathParams = new HashMap<>();
    private final Map<String, String> queryParams = new HashMap<>();
    private FormBody.Builder formBuilder;
    private MultipartBody.Builder multipartBuilder;
    private RequestBody requestBody;
    private MediaType mediaType;

    /**
     * 构造函数，使用默认配置
     */
    public HttpClientBuilder() {
        this.client = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .build();
        this.requestBuilder = new Request.Builder();
    }

    /**
     * 构造函数，使用自定义 OkHttpClient
     * @param client 自定义的 OkHttpClient
     */
    public HttpClientBuilder(OkHttpClient client) {
        this.client = client;
        this.requestBuilder = new Request.Builder();
    }

    /**
     * 设置请求URL
     * @param baseUrl 请求地址
     * @return 当前对象
     */
    public HttpClientBuilder baseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
        return this;
    }

    /**
     * 添加请求头
     * @param name 头名称
     * @param value 头值
     * @return 当前对象
     */
    public HttpClientBuilder addHeader(String name, String value) {
        this.requestBuilder.addHeader(name, value);
        return this;
    }

    /**
     * 设置请求头（会覆盖同名的头）
     * @param name 头名称
     * @param value 头值
     * @return 当前对象
     */
    public HttpClientBuilder setHeader(String name, String value) {
        this.requestBuilder.header(name, value);
        return this;
    }

    /**
     * 设置所有请求头
     * @param headers 头信息Map
     * @return 当前对象
     */
    public HttpClientBuilder headers(Map<String, String> headers) {
        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                this.requestBuilder.header(entry.getKey(), entry.getValue());
            }
        }
        return this;
    }

    /**
     * 初始化表单构造器
     * @return 当前对象
     */
    public HttpClientBuilder initForm() {
        this.formBuilder = new FormBody.Builder();
        return this;
    }

    /**
     * 添加表单参数
     * @param name 参数名
     * @param value 参数值
     * @return 当前对象
     */
    public HttpClientBuilder addFormParam(String name, String value) {
        if (this.formBuilder == null) {
            initForm();
        }
        this.formBuilder.add(name, value);
        return this;
    }

    /**
     * 添加多个表单参数
     * @param params 参数Map
     * @return 当前对象
     */
    public HttpClientBuilder addFormParams(Map<String, String> params) {
        if (params != null && !params.isEmpty()) {
            if (this.formBuilder == null) {
                initForm();
            }
            for (Map.Entry<String, String> entry : params.entrySet()) {
                this.formBuilder.add(entry.getKey(), entry.getValue());
            }
        }
        return this;
    }

    /**
     * 初始化多部分表单构造器
     * @return 当前对象
     */
    public HttpClientBuilder initMultipart() {
        this.multipartBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        return this;
    }

    /**
     * 添加多部分表单参数
     * @param name 参数名
     * @param value 参数值
     * @return 当前对象
     */
    public HttpClientBuilder addMultipartParam(String name, String value) {
        if (this.multipartBuilder == null) {
            initMultipart();
        }
        this.multipartBuilder.addFormDataPart(name, value);
        return this;
    }

    /**
     * 添加多部分表单文件
     * @param name 参数名
     * @param filename 文件名
     * @param file 文件字节数组
     * @param mediaType 媒体类型
     * @return 当前对象
     */
    public HttpClientBuilder addMultipartFile(String name, String filename, byte[] file, MediaType mediaType) {
        if (this.multipartBuilder == null) {
            initMultipart();
        }
        this.multipartBuilder.addFormDataPart(
                name,
                filename,
                RequestBody.create(file, mediaType)
        );
        return this;
    }

    /**
     * 设置请求体
     * @param body 请求体
     * @return 当前对象
     */
    public HttpClientBuilder body(RequestBody body) {
        this.requestBody = body;
        return this;
    }

    /**
     * 设置JSON请求体
     * @param json JSON字符串
     * @return 当前对象
     */
    public HttpClientBuilder jsonBody(String json) {
        this.mediaType = MediaType.parse("application/json; charset=utf-8");
        this.requestBody = new RequestBody() {
            @Override
            public void writeTo(@NotNull BufferedSink sink) throws IOException {
                sink.writeUtf8(json);
            }

            @Nullable
            @Override
            public MediaType contentType() {
                return mediaType;
            }
        };
        return this;
    }

    /**
     * 设置XML请求体
     * @param xml XML字符串
     * @return 当前对象
     */
    public HttpClientBuilder xmlBody(String xml) {
        this.mediaType = MediaType.parse("application/xml; charset=utf-8");
        this.requestBody = new RequestBody() {
            @Override
            public void writeTo(@NotNull BufferedSink sink) throws IOException {
                sink.writeUtf8(xml);
            }

            @Nullable
            @Override
            public MediaType contentType() {
                return mediaType;
            }
        };
        return this;
    }

    /**
     * 执行GET请求
     * @return 响应结果
     * @throws IOException 如果请求失败
     */
    public Response get() throws IOException {
        return executeRequest("GET");
    }

    /**
     * 执行POST请求
     * @return 响应结果
     * @throws IOException 如果请求失败
     */
    public Response post() throws IOException {
        return executeRequest("POST");
    }

    /**
     * 执行PUT请求
     * @return 响应结果
     * @throws IOException 如果请求失败
     */
    public Response put() throws IOException {
        return executeRequest("PUT");
    }

    /**
     * 执行DELETE请求
     * @return 响应结果
     * @throws IOException 如果请求失败
     */
    public Response delete() throws IOException {
        return executeRequest("DELETE");
    }

    /**
     * 执行PATCH请求
     * @return 响应结果
     * @throws IOException 如果请求失败
     */
    public Response patch() throws IOException {
        return executeRequest("PATCH");
    }

    /**
     * 执行HEAD请求
     * @return 响应结果
     * @throws IOException 如果请求失败
     */
    public Response head() throws IOException {
        return executeRequest("HEAD");
    }

    /**
     * 执行自定义方法请求
     * @param method 请求方法
     * @return 响应结果
     * @throws IOException 如果请求失败
     */
    public Response execute(String method) throws IOException {
        return executeRequest(method);
    }

    /**
     * 异步执行GET请求
     * @param callback 回调接口
     */
    public void getAsync(Callback callback) {
        executeRequestAsync("GET", callback);
    }

    /**
     * 异步执行POST请求
     * @param callback 回调接口
     */
    public void postAsync(Callback callback) {
        executeRequestAsync("POST", callback);
    }

    /**
     * 异步执行PUT请求
     * @param callback 回调接口
     */
    public void putAsync(Callback callback) {
        executeRequestAsync("PUT", callback);
    }

    /**
     * 异步执行DELETE请求
     * @param callback 回调接口
     */
    public void deleteAsync(Callback callback) {
        executeRequestAsync("DELETE", callback);
    }

    /**
     * 异步执行PATCH请求
     * @param callback 回调接口
     */
    public void patchAsync(Callback callback) {
        executeRequestAsync("PATCH", callback);
    }

    /**
     * 异步执行HEAD请求
     * @param callback 回调接口
     */
    public void headAsync(Callback callback) {
        executeRequestAsync("HEAD", callback);
    }

    /**
     * 异步执行自定义方法请求
     * @param method 请求方法
     * @param callback 回调接口
     */
    public void executeAsync(String method, Callback callback) {
        executeRequestAsync(method, callback);
    }

    private Response executeRequest(String method) throws IOException {
        if (baseUrl == null || baseUrl.isEmpty()) {
            throw new IllegalArgumentException("URL must not be null or empty");
        }

        Request request = buildRequest(method);

        logger.info("Executing request  URL: {}", request.url());
        return client.newCall(request).execute();
    }

    private void executeRequestAsync(String method, Callback callback) {
        if (baseUrl == null || baseUrl.isEmpty()) {
            throw new IllegalArgumentException("URL must not be null or empty");
        }

        Request request = buildRequest(method);
        client.newCall(request).enqueue(callback);
    }

    public HttpClientBuilder addPathParam(String key, String value) {
        pathParams.put(key, value);
        return this;
    }

    public HttpClientBuilder addQueryParam(String key, String value) {
        if(StringUtils.isNotBlank(value)) {
            queryParams.put(key, URLEncoder.encode(value, StandardCharsets.UTF_8));
        } else {
            queryParams.put(key, null);
        }

        return this;
    }

    /**
     * 构建完整URL（含查询参数）
     */
    private String buildFullUrl() {
        String url = this.baseUrl;

        for (Map.Entry<String, String> entry : pathParams.entrySet()) {
            String placeholder = "{" + entry.getKey() + "}";
            url = url.replace(placeholder, encodePathParam(entry.getValue()));
        }

        if (!queryParams.isEmpty()) {
            String queryString = queryParams.entrySet().stream()
                    .map(entry -> entry.getKey() + "=" + entry.getValue())
                    .collect(Collectors.joining("&"));
            url += "?" + queryString;
        }
        return url;
    }

    /**
     * 路径参数编码（特殊字符处理）
     */
    private String encodePathParam(String value) {
        return URLEncoder.encode(value, StandardCharsets.UTF_8)
                .replaceAll("%2F", "/")
                .replaceAll("%3A", ":");
    }

    private Request buildRequest(String method) {
        String url = this.buildFullUrl();
        requestBuilder.url(url);

        // 设置请求体和请求方法
        if (requestBody != null) {
            requestBuilder.method(method, requestBody);
        } else if (formBuilder != null) {
            requestBuilder.method(method, formBuilder.build());
        } else if (multipartBuilder != null) {
            requestBuilder.method(method, multipartBuilder.build());
        } else if (!method.equalsIgnoreCase("GET") && !method.equalsIgnoreCase("HEAD")) {
            // 对于非GET和HEAD请求，如果没有请求体，添加一个空的请求体
            requestBuilder.method(method, RequestBody.create(new byte[0]));
        } else {
            requestBuilder.method(method, null);
        }

        return requestBuilder.build();
    }
}
